package top.mcwebsite.lib.serviceManager.plugin

import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.tree.ClassNode
import top.mcwebsite.lib.transform.api.TransformContext
import top.mcwebsite.lib.transform.api.Transformer

class ServiceManagerTransformer : Transformer {

    private val serviceImplProviders = mutableSetOf<String>()

    override fun isNeedScan(): Boolean {
        return true
    }

    override fun onBeforeTransform(context: TransformContext) {
    }

    override fun scan(path: String, byteArraySupplier: () -> ByteArray) {
        if (!path.contains(PREFIX_SERVICE_PROVIDER)) {
            return
        }
        val start = path.indexOf(PREFIX_SERVICE_PROVIDER)
        val end = path.length - DOT_CLASS_LENGTH
        val className = path.substring(start, end).let {
            if (it.contains("$")) {
                it.substring(0, it.indexOf("$"))
            } else {
                it
            }
        }
        serviceImplProviders.add(className)
    }

    override fun transform(byteArray: ByteArray): ByteArray {
        val reader = ClassReader(byteArray)
        val classNode = ClassNode()
        reader.accept(classNode, 0)
        return if (classNode.name.contains(INJECT_CLASS_NAME)) {
            println("service provider = $serviceImplProviders")
            val writer = ClassWriter(reader, 0)
            val visitor = InjectServiceProviderCodeClassVisitor(writer, serviceImplProviders)
            reader.accept(visitor, 0)
            writer.toByteArray()
        } else {
            byteArray
        }
    }

    override fun onAfterTransform(context: TransformContext) {
    }

    companion object {

        private const val DOT_CLASS = ".class"
        const val DOT_CLASS_LENGTH = DOT_CLASS.length
        const val PREFIX_SERVICE_PROVIDER = "top/mcwebsite/lib/serviceManager/ServiceProvider"
        const val INJECT_CLASS_NAME = "ServiceImplProviderInject"

    }
}